﻿using Aspose.Cells;
using AWSV2.Models;
using System;
using System.Windows;
using System.Data;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections.Generic;
using AWSV2.Services;
using System.Configuration;
using System.Reflection;
using System.Linq;
using System.Collections.ObjectModel;
using System.Windows.Media;
using Common.Utility.AJ.Extension;
using MaterialDesignExtensions.Controls;
using Common.Utility.AJ.MobileConfiguration;
using Common.Converters;
using Common.Utility.AJ;
using Stylet;
using Common.Utility;
using AWSV2.ViewModels.ShellViewHomeTemplate;
using Masuit.Tools;
using Common.Model;
using LiveChartsCore.VisualElements;
using Common.Models;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Common.EF.Controllers;
using Masuit.Tools.Models;
using static System.Resources.ResXFileRef;
using static System.Runtime.InteropServices.JavaScript.JSType;
using FFmpeg.AutoGen;
using DocumentFormat.OpenXml.Wordprocessing;
using Quartz.Util;
using SixLabors.ImageSharp.Formats;
using Common.AJControls;
using Common;
using Common.LPR;

namespace AWSV2.ViewModels
{
    public class WeighFormViewModel : Screen
    {
        public event EventHandler ManualInputCarNoCompleted;

        private bool _carPlateNumberKeyboardVisible;
        public bool CarPlateNumberKeyboardVisible
        {
            get => _carPlateNumberKeyboardVisible;
            set => SetAndNotify(ref _carPlateNumberKeyboardVisible, value);
        }

        private AJFilePicker.AJUploadOptions _fileUploadOptions;
        public AJFilePicker.AJUploadOptions FileUploadOptions
        {
            get => _fileUploadOptions;
            set => SetAndNotify(ref _fileUploadOptions, value);
        }

        /// <summary>
        /// 当前临时称重记录
        /// </summary>
        private WeighingRecord _source;
        public WeighingRecord Source
        {
            get => _source;
            set
            {
                if (SetAndNotify(ref _source, value))
                {
                    if ((Fields?.Count).GetValueOrDefault() == 0)
                    {
                        return;
                    }

                    Refresh();
                }
            }
        }


        private WeighingRecord _relativeData;
        /// <summary>
        /// 由磅单关联触发的关联数据这里存一份 Submit 方法会重新合并一次 --阿吉 2024年12月19日14点44分
        /// </summary>
        public WeighingRecord RelativeData
        {
            get => _relativeData;
        }


        private ObservableCollection<DynamicPoundFieldItem> _fields;
        public ObservableCollection<DynamicPoundFieldItem> Fields
        {
            get => _fields;
            set => SetAndNotify(ref _fields, value);
        }

        private readonly Dictionary<string, Func<bool, Autocomplete, Task<object>>> AutocompleteCtrlSourceProcessMaps;

        private AppSettingsSection _mainSetting;

        private static readonly string[] _ignoreFields = WeighingRecord.GetPoundIgnoreFields();

        private static readonly string[] _readonlyTextBoxFields =
        [
            nameof(WeighingRecord.Bh),
            nameof(WeighingRecord.AutoNo),
            nameof(WeighingRecord.Mzrq),
            nameof(WeighingRecord.Pzrq),
            nameof(WeighingRecord.Jzrq),
            nameof(WeighingRecord.EntryTime),
            nameof(WeighingRecord.ExitDate),
            nameof(WeighingRecord.IsUpload),
        ];

        public WeighFormViewModel(AppSettingsSection mainSetting)
        {
            _mainSetting = mainSetting;
            Source = new WeighingRecord();
            FileUploadOptions = new AJFilePicker.AJUploadOptions
            {
                BeforeUploadHandle = () =>
                {
                    if (string.IsNullOrWhiteSpace(GetFormFieldValue(nameof(Source.Ch))))
                    {
                        MessageBoxExt.Alert(I18NService.Translate(LangKeys.车牌号未识别无法上传));
                        return false;
                    }
                    return true;
                },
                CustomFileNameHandle = (picker) =>
                {
                    if(picker.DataContext is DynamicPoundFieldItem item)
                    {
                        var ch = GetFormFieldValue(nameof(Source.Ch));
                        return System.IO.Path.Combine(LPRService.LPRSavePath, ch, $"{item.Field}_{DateTime.Now.ToString("yyyyMMddHHmmss")}");
                    }
                    return string.Empty;
                }
            };
        }

        public async void TriggerRelationCheckAsync(DynamicPoundFieldItem item,
            string @param)
        {
            if (item == null || string.IsNullOrWhiteSpace(@param))
            {
                return;
            }
            using var db = AJDatabaseService.GetDbContext();
            var propName = item.Field;

            var relation = await db.WeighingRecordRelations.Include(p => p.Children)
                .FirstOrDefaultAsync(p =>
                p.PropertyName == propName
                && p.PropertyValue == param && p.ParentId == null);

            if (relation == null || (relation.Children?.Count).GetValueOrDefault() == 0)
            {
                return;
            }
            _relativeData = new WeighingRecord();
            SetEntityProperty(item, true);
            foreach (var child in relation.Children)
            {
                SetFormFieldValue(child.PropertyName, child.PropertyValue);
                var itemInner = Fields.FirstOrDefault(p => p.Field == child.PropertyName);
                if (itemInner != null)
                {
                    SetEntityProperty(itemInner, true);
                }
            }
        }

        public void RaiseManualInputCarNoEvent(string carNo)
        {
            ManualInputCarNoCompleted?.Invoke(carNo, new EventArgs());
            CarPlateNumberKeyboardVisible = false;
        }

        public async void CustomerChangeAsync(string customerName)
        {
            var goodsFieldName = nameof(Source.Wz);

            var goodsField = Fields.FirstOrDefault(p => p.Field == goodsFieldName);

            var goodsPriceFieldName = nameof(Source.GoodsPrice);

            var goodsPriceField = Fields.FirstOrDefault(p => p.Field == goodsPriceFieldName);

            if (goodsField == null || goodsPriceFieldName == null)
            {
                return;
            }

            var goodsId = -1L;
            var goodsPrice = 0m;
            using var db = AJDatabaseService.GetDbContext();
            if (!string.IsNullOrWhiteSpace(goodsField.Value))
            {
                var name = goodsField.Value;
                var goodsItem = await db.Goods.AsNoTracking().FirstOrDefaultAsync(p => p.Name == name);
                goodsId = (goodsItem?.Id).GetValueOrDefault();
                goodsPrice = (goodsItem?.Price).GetValueOrDefault();
            }

            var currentCustomer = await db.Customers.AsNoTracking().FirstOrDefaultAsync(p => p.Name == customerName);
            var currentCustomerId = (currentCustomer?.Id).GetValueOrDefault();

            var goodsVSCustomerPrice = await db.GoodsVsCustomerPrices
                .FirstOrDefaultAsync(p => p.CustomerId == currentCustomerId && p.GoodsId == goodsId);

            var price = (goodsVSCustomerPrice?.Price ?? goodsPrice);

            if (goodsPriceField != null)
            {
                goodsPriceField.Value = price.ToString();
                Source.GoodsPrice = price;
            }
        }

        public async void GoodsChangeAsync(string goodsName)
        {
            var specFieldName = nameof(Source.GoodsSpec);

            var goodsSpecField = Fields.FirstOrDefault(p => p.Field == specFieldName);

            if (goodsSpecField == null)
            {
                return;
            }

            using var db = AJDatabaseService.GetDbContext();

            var detail = await db.Goods.Include(p => p.SpecList).AsNoTracking().FirstOrDefaultAsync(p => p.Name == goodsName);

            var specList = detail?.SpecList ?? new List<Common.EF.Tables.GoodsSpec>();

            goodsSpecField.Options = new ObservableCollection<Common.AJControls.AJMultiSelect.AJMultiSelectOptionItem>(specList.Select(p => new Common.AJControls.AJMultiSelect.AJMultiSelectOptionItem
            {
                Label = p.Name,
                Value = p.Name
            }));

            goodsSpecField.SelectedOption = goodsSpecField.Options.FirstOrDefault();
            Source.Wz = goodsName;
            Source.GoodsSpec = specList.FirstOrDefault()?.Name;

            var customerFieldName = nameof(Source.Kh);
            var customerField = Fields.FirstOrDefault(p => p.Field == customerFieldName);

            var goodsPriceFieldName = nameof(Source.GoodsPrice);

            var goodsPriceField = Fields.FirstOrDefault(p => p.Field == goodsPriceFieldName);

            if (goodsPriceField != null)
            {
                var cusomerId = -1L;
                if (!string.IsNullOrWhiteSpace(customerField?.Value))
                {
                    var customerName = customerField.Value;
                    var customer = await db.Customers.AsNoTracking().FirstOrDefaultAsync(p => p.Name == customerName);

                    cusomerId = (customer?.Id).GetValueOrDefault();
                }

                var goodsId = detail?.Id;

                var goodsVSCustomerPrice = await db.GoodsVsCustomerPrices
                    .FirstOrDefaultAsync(p => p.CustomerId == cusomerId && p.GoodsId == goodsId);
                var price = (goodsVSCustomerPrice?.Price ?? detail?.Price).GetValueOrDefault();

                goodsPriceField.Value = price.ToString();
                Source.GoodsPrice = price;
            }

        }

        public void SwitchTemplate(AppSettingsSection mainSettings, IEnumerable<DynamicPoundFieldItem> fields,
            HomeTemplateType homeTemplateType = HomeTemplateType.Default)
        {
            _mainSetting = mainSettings;

            // 只取出来是表单显示的,排除所有忽略字段
            var source = fields.Where(p => !_ignoreFields.Contains(p.Field) && p.IsFormDisplay).ToList();

            var weighingControl = _mainSetting.Settings["WeighingControl"].TryGetString();
            var autoMode = !(weighingControl.Equals("Hand") || weighingControl.Equals("Btn"));

            foreach (var item in source)
            {
                if (autoMode)
                {
                    item.Disabled = true;
                }
                else
                {
                    // 这个绑定只读, 赋值True表示可以输入, 否则就是不能输入
                    item.IsFilterDisplay = !_readonlyTextBoxFields.Contains(item.Field);
                    item.Disabled = _readonlyTextBoxFields.Contains(item.Field);
                }
            }

            Fields = new ObservableCollection<DynamicPoundFieldItem>(source);

        }

        public string GetFormFieldValue(string propName)
        {
            return Fields.FirstOrDefault(p => p.Field == propName)?.Value ?? string.Empty;
        }

        public void SetFormFieldValue(string propName, object value)
        {
            var field = Fields.FirstOrDefault(p => p.Field == propName);
            if (field == null)
            {
                return;
            }

            // 车牌特殊处理
            if (field.Field == nameof(WeighingRecord.Ch))
            {
                var ch = value as string;
                var option = field.Options.FirstOrDefault(p => ch == (p.Value as string));
                if (option == null)
                {
                    option = new Common.AJControls.AJMultiSelect.AJMultiSelectOptionItem
                    {
                        Label = ch,
                        Value = ch,
                    };

                    field.Options.Add(option);
                    field.AutoCompleteSource.AddIfNotExist(ch);
                }
                field.SelectedOption = option;
                return;
            }
            // 车牌颜色特殊处理
            if (field.Field == nameof(WeighingRecord.PlateColor))
            {
                if (Enum.TryParse(typeof(CarPlateColor), value?.ToString(), out var color))
                {
                    field.SelectedOption = field.Options.FirstOrDefault(p => (CarPlateColor)color == (CarPlateColor)p.Value);
                }
                return;
            }
            // 日期类型特殊处理
            var entityProp = Source.GetType().GetProperty(propName);
            if (entityProp != null)
            {
                if (entityProp.PropertyType == typeof(DateTime?)
                    || entityProp.PropertyType == typeof(DateTime))
                {
                    if (DateTime.TryParse(value?.ToString(), out var date))
                    {
                        field.Value = date.ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    return;
                }
                // 布尔类型特殊处理
                if (entityProp.PropertyType == typeof(bool))
                {
                    var intVal = (value?.ToString()).TryGetInt();
                    field.SelectedOption = field.Options.FirstOrDefault(p => (int)p.Value == intVal);
                    return;
                }
            }

            var type = Enum.Parse<VbenAdminFormType>(field.FormType);

            var strVal = value?.ToString() ?? string.Empty;

            switch (type)
            {
                case VbenAdminFormType.Select:
                case VbenAdminFormType.AutoComplete:

                    var option = field.Options.FirstOrDefault(p => strVal == (p.Value as string));
                    if (option == null)
                    {
                        option = new Common.AJControls.AJMultiSelect.AJMultiSelectOptionItem
                        {
                            Label = strVal,
                            Value = strVal,
                        };

                        field.Options.Add(option);
                        field.AutoCompleteSource.AddIfNotExist(strVal);
                    }

                    field.SelectedOption = field.Options.FirstOrDefault(p => (p.Value as string) == strVal || strVal == p.Label);
                    break;
                case VbenAdminFormType.Input:
                case VbenAdminFormType.InputNumber:
                case VbenAdminFormType.FilePicker:
                    field.Value = strVal;
                    break;
                default:
                    break;
            }

        }

        /// <summary>
        /// 将动态表单条目中的值赋值给实体表单模型
        /// </summary>
        public void Submit()
        {
            foreach (var item in Fields)
            {
                SetEntityProperty(item);
            }
            _relativeData = null;
        }

        public void Refresh(bool reset = false)
        {
            for (int i = 0; i < Fields.Count; i++)
            {
                var type = Enum.Parse<VbenAdminFormType>(Fields[i].FormType);
                var item = Fields[i];
                switch (type)
                {
                    case VbenAdminFormType.Select:
                    case VbenAdminFormType.AutoComplete:

                        if (reset)
                        {
                            Fields[i].SelectedOption = null;
                            ClearEntityProperty(ref item);
                        }
                        else
                        {
                            FillFormFieldWithEntity(ref item);
                        }


                        break;
                    case VbenAdminFormType.Input:
                    case VbenAdminFormType.InputNumber:
                    case VbenAdminFormType.DatePicker:
                    case VbenAdminFormType.RangePicker:
                    case VbenAdminFormType.FilePicker:

                        if (reset)
                        {
                            item.Value = string.Empty;
                            ClearEntityProperty(ref item);
                        }
                        else
                        {
                            FillFormFieldWithEntity(ref item);
                        }

                        break;

                    default:
                        break;
                }
            }

        }

        private void ClearEntityProperty(ref DynamicPoundFieldItem item)
        {
            var entityProp = Source.GetType().GetProperty(item.Field);
            if (entityProp == null)
            {
                return;
            }

            if (entityProp.Name == nameof(Source.PlateColor))
            {
                entityProp.SetValue(Source, CarPlateColor.未知);
                return;
            }

            if (entityProp.PropertyType == typeof(DateTime))
            {
                entityProp.SetValue(Source, DateTime.Now);
                return;
            }

            if (entityProp.PropertyType == typeof(DateTime?))
            {
                entityProp.SetValue(Source, null);
                return;
            }

            if (entityProp.PropertyType == typeof(bool))
            {
                entityProp.SetValue(Source, false);
                return;
            }

            if (entityProp.PropertyType != typeof(string))
            {
                return;
            }

            entityProp.SetValue(Source, null);
        }

        private void SetEntityProperty(DynamicPoundFieldItem item, bool fillRelativeData = false)
        {
            var entityProp = fillRelativeData
                ? _relativeData.GetType().GetProperty(item.Field)
                : Source.GetType().GetProperty(item.Field);
            if (entityProp == null)
            {
                return;
            }

            if (entityProp.Name == nameof(Source.PlateColor))
            {
                if (Enum.TryParse(typeof(CarPlateColor), item.Value, out var color))
                {
                    entityProp.SetValue(Source, color);
                }
                return;
            }

            if (entityProp.PropertyType == typeof(DateTime)
                || entityProp.PropertyType == typeof(DateTime?))
            {
                if (DateTime.TryParse(item.Value, out var date))
                {
                    entityProp.SetValue(Source, date);
                }
                return;
            }

            if (entityProp.PropertyType == typeof(bool))
            {
                entityProp.SetValue(Source, item.Value.TryGetBoolean());
                return;
            }

            if (entityProp.PropertyType != typeof(string))
            {
                return;
            }

            entityProp.SetValue(fillRelativeData ? _relativeData : Source, item.Value);

        }

        private void FillFormFieldWithEntity(ref DynamicPoundFieldItem item)
        {
            var entityProp = Source.GetType().GetProperty(item.Field);
            if (entityProp == null)
            {
                return;
            }

            if (entityProp.Name == nameof(Source.PlateColor))
            {
                var color = (CarPlateColor)entityProp.GetValue(Source);
                item.SelectedOption = item.Options.FirstOrDefault(p => (CarPlateColor)p.Value == color);
                return;
            }

            if (entityProp.PropertyType == typeof(DateTime))
            {
                item.Value = ((DateTime)entityProp.GetValue(Source)).ToString("yyyy-MM-dd HH:mm:ss");
                return;
            }

            if (entityProp.PropertyType == typeof(DateTime?))
            {
                var date = (DateTime?)entityProp.GetValue(Source);
                item.Value = date == null ? string.Empty : date.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss");
                return;
            }

            if (entityProp.PropertyType != typeof(string))
            {
                return;
            }

            item.Value = entityProp.GetValue(Source) as string;
        }
    }

    public class DynamicFormItemTemplateSelector : DataTemplateSelector
    {
        public DataTemplate Combox { get; set; }

        public DataTemplate TextBox { get; set; }

        public DataTemplate FilePicker { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item == null)
            {
                return null;
            }
            if (item is DynamicPoundFieldItem fieldItem)
            {
                if (Enum.TryParse(fieldItem.FormType, true, out VbenAdminFormType fType))
                {
                    switch (fType)
                    {
                        case VbenAdminFormType.Select:
                        case VbenAdminFormType.AutoComplete:
                            return Combox;
                        case VbenAdminFormType.Input:
                        case VbenAdminFormType.InputNumber:
                        case VbenAdminFormType.DatePicker:
                        case VbenAdminFormType.RangePicker:
                            return TextBox;
                        case VbenAdminFormType.FilePicker:
                            return FilePicker;
                        default:
                            break;
                    }
                }

                return null;
            }
            return null;
        }
    }
}
